/**
 * Project: gateway-pay
 * File Created at 2016年4月20日
 * ouyangjixin
 * Copyright 2014 XunLei.com Corporation Limited.
 * All rights reserved.
 * This software is the confidential and proprietary information of
 * XunLei Company. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with XunLei.com.
 */
package pub.pjoc.util.http;

import com.google.common.base.Strings;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * @author xiongyingqi
 * @since 2016-09-18
 */
public abstract class HttpUtils {
  private static final Logger logger = LoggerFactory.getLogger(HttpUtils.class);

  public static final int DEFAULT_TIMEOUT = 6000;
  public static final String DEFAULT_CHARSET = "UTF-8";

  public static HttpClient getClient(int timeout) {
    if (timeout <= 0) { // 不允许设置不超时连接
      timeout = DEFAULT_TIMEOUT;
    }
    RequestConfig.Builder requestBuilder = RequestConfig.custom();
    requestBuilder = requestBuilder.setSocketTimeout(timeout);
    requestBuilder.setConnectTimeout(timeout);
    requestBuilder.setConnectionRequestTimeout(timeout);

    CloseableHttpClient client = HttpClientBuilder
        .create()
        .setDefaultRequestConfig(requestBuilder.build())
        .build();
    return client;

  }

  public static HttpClient getClient() {
    return getClient(DEFAULT_TIMEOUT);

  }

  /**
   * @param request
   * @return
   */
  public static String executeRequest(HttpRequestBase request, String charset, int timeout) {
    if (Strings.isNullOrEmpty(charset)) {
      charset = DEFAULT_CHARSET;
    }
    HttpResponse response = null;
    String result = null;
    try {
      HttpClient client = getClient(timeout);
      if (client == null) {
        logger.error("Failed to get httpclient!");
        return null;
      }
      response = client.execute(request);
      if (response == null) {
        logger.error("response is null!");
        return null;
      }
      int statusCode = response.getStatusLine().getStatusCode();
      if (statusCode != HttpStatus.SC_OK) {
        logger.error("statusCode: {}", statusCode);
        return null;
      }
      HttpEntity entity = response.getEntity();
      result = EntityUtils.toString(entity, charset);
    } catch (Exception e) {
      logger.error("Http error with message: " + e.getMessage(), e);
      return null;
    } finally {
      releaseConnection(request);
    }
    return result;
  }

  /**
   * @param request
   */
  private static void releaseConnection(HttpRequestBase request) {
    if (request != null) {
      request.releaseConnection();
    }
  }

  /**
   * @param postUrl
   * @param reqEntity
   * @return
   */
  public static String post(String postUrl, HttpEntity reqEntity, String charset, int timeout) {
    HttpPost httpPost = new HttpPost(postUrl);
    httpPost.setEntity(reqEntity);
    String response = executeRequest(httpPost, charset, timeout);
    if (logger.isDebugEnabled()) {
      try {
        logger.debug("Sent post to url: {} with request: {}", postUrl, EntityUtils.toString(reqEntity,
            charset));
      } catch (IOException e) {
        logger.error("", e);
      }
    }
    return response;
  }

  public static String post(String postUrl, String content, String charset, int timeout) {
    StringEntity entity = new StringEntity(content, charset);
    entity.setContentType(URLEncodedUtils.CONTENT_TYPE);
    return post(postUrl, entity, charset, timeout);
  }

  public static String buildUrlParams(String url,
                                      Map<String, String> params) {
    if (params == null || params.isEmpty()) {
      return url;
    }
    StringBuilder builder = new StringBuilder(url);
    if (!url.contains("?")) {
      builder.append("?");
    } else {
      builder.append("&");
    }
    String httpParameters = parseMapToHttpParameters(params);
    builder.append(httpParameters);

    String substring = builder.substring(0, builder.length() - 1);
    return substring;
  }

  public static String parseMapToHttpParameters(Map<String, String> parameters) {
    StringBuilder builder = new StringBuilder();
    for (Iterator<Map.Entry<String, String>> iterator = parameters.entrySet().iterator(); iterator
        .hasNext(); ) {
      Map.Entry<String, String> entry = iterator.next();
      String key = entry.getKey();
      String value = entry.getValue();
      if (Strings.isNullOrEmpty(key)) {
        continue;
      }
      builder.append(key);
      builder.append("=");
      builder.append(value);
      if (iterator.hasNext()) {
        builder.append("&");
      }
    }
    return builder.toString();
  }

  public static List<NameValuePair> parseMapToPairs(Map<String, String> parameters) {
    if (parameters == null) {
      return null;
    }
    List<NameValuePair> pairs = new ArrayList<NameValuePair>(parameters.size());
    for (Map.Entry<String, String> entry : parameters.entrySet()) {
      String key = entry.getKey();
      String value = entry.getValue();
      NameValuePair pair = new BasicNameValuePair(key, value);
      pairs.add(pair);
    }
    return pairs;
  }
}
